/*
 * Copyright (c) 2017. 杭州端点网络科技有限公司.  All rights reserved.
 */

package com.jiantong.user.impl.service;

import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jiantong.user.dto.OrganizationSuggestion;
import com.jiantong.user.enums.OrganizationType;
import com.jiantong.user.impl.dao.BreedFactoryDao;
import com.jiantong.user.impl.dao.ButcherFactoryDao;
import com.jiantong.user.impl.dao.GovernmentDao;
import com.jiantong.user.impl.dao.OrganizationDao;
import com.jiantong.user.model.BreedFactory;
import com.jiantong.user.model.ButcherFactory;
import com.jiantong.user.model.Government;
import com.jiantong.user.model.Organization;
import com.jiantong.user.service.OrganizationReadService;
import io.terminus.boot.rpc.common.annotation.RpcProvider;
import io.terminus.common.exception.ServiceException;
import io.terminus.common.model.PageInfo;
import io.terminus.common.model.Paging;
import io.terminus.common.model.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author : panxin
 */
@Slf4j
@Service
@RpcProvider
public class OrganizationReadServiceImpl implements OrganizationReadService {

    private final OrganizationDao organizationDao;
    private final ButcherFactoryDao butcherFactoryDao;
    private final BreedFactoryDao breedFactoryDao;
    private final GovernmentDao governmentDao;

    @Autowired
    public OrganizationReadServiceImpl(OrganizationDao organizationDao, ButcherFactoryDao butcherFactoryDao, BreedFactoryDao breedFactoryDao, GovernmentDao governmentDao) {
        this.organizationDao = organizationDao;
        this.butcherFactoryDao = butcherFactoryDao;
        this.breedFactoryDao = breedFactoryDao;
        this.governmentDao = governmentDao;
    }

    @Override
    public Response<Organization> findById(Long id) {
        try {
            Organization org = organizationDao.findById(id);
            if (org == null) {
                log.error("organization not exists id = {}", id);
                return Response.fail("organization.not.exists");
            }
            return Response.ok(org);
        } catch (Exception e) {
            log.error("failed to find organization by id = {}, cause : {}",
                    id, Throwables.getStackTraceAsString(e));
            return Response.fail("find.organization.failed");
        }
    }

    @Override
    public Response<Optional<Organization>> findOptionalById(Long id) {
        try {
            return Response.ok(Optional.fromNullable(organizationDao.findById(id)));
        } catch (Exception e) {
            log.error("failed to find organization by id = {}, cause : {}",
                    id, Throwables.getStackTraceAsString(e));
            return Response.fail("find.organization.failed");
        }
    }

    @Override
    public Response<? extends Organization> findByIdAndType(Long id, OrganizationType type) {
        try {
            Organization org = null;
            switch (type) {
                case GOVERNMENT:
                    org = governmentDao.findById(id);
                    break;
                case BUTCHER:
                    org = butcherFactoryDao.findById(id);
                    break;
                case BREEDER:
                    org = breedFactoryDao.findById(id);
                    break;
                default:
                    throw new ServiceException("organization.type.undefined");
            }

            if (org == null) {
                log.error("organization not exists id = {}", id);
                return Response.fail("organization.not.exists");
            }
            return Response.ok(org);
        } catch (Exception e) {
            log.error("failed to find organization by id = {}, cause : {}",
                    id, Throwables.getStackTraceAsString(e));
            return Response.fail("find.organization.failed");
        }
    }

    @Override
    public Response<List<OrganizationSuggestion>> suggestByNameAndType(String name, OrganizationType type) {
        try {
            if (Strings.isNullOrEmpty(name)) {
                return Response.ok(Collections.emptyList());
            }

            List<? extends Organization> organizations = null;
            switch (type) {
                case GOVERNMENT:
                    organizations = listGovernmentByName(name);
                    break;
                case BUTCHER:
                    organizations = listButcherFactoryByName(name);
                    break;
                case BREEDER:
                    organizations = listBreederFactoryByName(name);
                    break;
                default:
                    throw new ServiceException("organization.type.undefined");
            }

            return Response.ok(generateSuggestion(organizations));
        } catch (Exception e) {
            log.error("failed to suggest organization by name = {}, type = {}, cause : {}",
                    name, type, Throwables.getStackTraceAsString(e));
            return Response.fail("find.organization.failed");
        }
    }



    private List<OrganizationSuggestion> generateSuggestion(List<? extends Organization> organizations) {
        List<OrganizationSuggestion> suggestionList = Lists.newArrayListWithCapacity(organizations.size());
        OrganizationSuggestion suggestion = null;
        for (Organization organization : organizations) {
            suggestion = new OrganizationSuggestion();
            suggestion.setId(organization.getId());
            suggestion.setName(organization.getName());
            suggestionList.add(suggestion);
        }
        return suggestionList;
    }

    private List<? extends Organization> listBreederFactoryByName(String name) {
        Integer pageNo = 1;
        Integer pageSize = 20;
        Map<String, Object> criteria = Maps.newHashMap();
        criteria.put("name", name);

        List<BreedFactory> breedFactories = Lists.newArrayList();
        while (true) {
            PageInfo pageInfo = new PageInfo(pageNo, pageSize);
            Paging<BreedFactory> paging = breedFactoryDao.paging(pageInfo.getOffset(), pageInfo.getLimit(), criteria);
            List<BreedFactory> data = paging.getData();
            if (data.isEmpty()) {
                break;
            }
            breedFactories.addAll(data);
            pageNo++;
        }
        return breedFactories;
    }

    private List<? extends Organization> listButcherFactoryByName(String name) {
        Integer pageNo = 1;
        Integer pageSize = 20;
        Map<String, Object> criteria = Maps.newHashMap();
        criteria.put("name", name);

        List<ButcherFactory> butcherFactories = Lists.newArrayList();
        while (true) {
            PageInfo pageInfo = new PageInfo(pageNo, pageSize);
            Paging<ButcherFactory> paging = butcherFactoryDao.paging(pageInfo.getOffset(), pageInfo.getLimit(), criteria);
            List<ButcherFactory> data = paging.getData();
            if (data.isEmpty()) {
                break;
            }
            butcherFactories.addAll(data);
            pageNo++;
        }
        return butcherFactories;
    }

    private List<? extends Organization> listGovernmentByName(String name) {
        Integer pageNo = 1;
        Integer pageSize = 20;
        Map<String, Object> criteria = Maps.newHashMap();
        criteria.put("name", name);

        List<Government> butcherFactories = Lists.newArrayList();
        while (true) {
            PageInfo pageInfo = new PageInfo(pageNo, pageSize);
            Paging<Government> paging = governmentDao.paging(pageInfo.getOffset(), pageInfo.getLimit(), criteria);
            List<Government> data = paging.getData();
            if (data.isEmpty()) {
                break;
            }
            butcherFactories.addAll(data);
            pageNo++;
        }
        return butcherFactories;
    }


    @Override
    public Response<List<Organization>> selectList(Map criteria) {
        return Response.ok(organizationDao.organList(criteria));
    }

}
